"""
企业级金融数据MCP服务系统 - 指数数据模型
提供完整的指数相关数据SQLAlchemy ORM模型定义
"""

from datetime import datetime, date
from decimal import Decimal
from typing import Optional, Dict, Any
from sqlalchemy import String, DateTime, Date, Boolean, Integer, Numeric, Text, Index, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.dialects.postgresql import JSONB

from .base import BaseFinancialModel, DataVersionMixin, SyncStatusMixin, PartitionMixin


class IndexBasicInfo(BaseFinancialModel):
    """
    指数基本信息模型
    存储各类指数的基本信息
    """
    __tablename__ = "index_basic_info"
    
    # 指数代码
    index_code: Mapped[str] = mapped_column(String(20), primary_key=True, comment="指数代码")
    
    # 指数名称
    index_name: Mapped[str] = mapped_column(String(200), nullable=False, comment="指数名称")
    
    # 指数英文名称
    index_name_en: Mapped[Optional[str]] = mapped_column(String(200), nullable=True, comment="指数英文名称")
    
    # 指数类型：股票指数, 债券指数, 商品指数, 货币指数等
    index_type: Mapped[str] = mapped_column(String(50), nullable=False, comment="指数类型")
    
    # 指数分类：综合指数, 行业指数, 主题指数, 规模指数等
    index_category: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="指数分类")
    
    # 基期
    base_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="基期")
    
    # 基点
    base_point: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 6), nullable=True, comment="基点")
    
    # 发布日期
    launch_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="发布日期")
    
    # 计算方法：加权平均, 等权重, 价格加权等
    calculation_method: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment="计算方法")
    
    # 样本数量
    sample_size: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="样本数量")
    
    # 权重上限(%)
    weight_cap: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2), nullable=True, comment="权重上限(%)")
    
    # 调整频率
    rebalance_frequency: Mapped[Optional[str]] = mapped_column(String(50), nullable=True, comment="调整频率")
    
    # 币种
    currency: Mapped[str] = mapped_column(String(10), nullable=False, default="CNY", comment="币种")
    
    # 交易所代码
    exchange_code: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="交易所代码")
    
    # 交易所名称
    exchange_name: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment="交易所名称")
    
    # 发布机构
    publisher: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment="发布机构")
    
    # 指数描述
    description: Mapped[Optional[str]] = mapped_column(Text, nullable=True, comment="指数描述")
    
    # 是否停止发布
    is_discontinued: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False, comment="是否停止发布")
    
    # 停止发布日期
    discontinue_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="停止发布日期")
    
    __table_args__ = (
        Index('idx_index_basic_name', 'index_name'),
        Index('idx_index_basic_type', 'index_type'),
        Index('idx_index_basic_category', 'index_category'),
        Index('idx_index_basic_exchange', 'exchange_code'),
        Index('idx_index_basic_publisher', 'publisher'),
        Index('idx_index_basic_launch_date', 'launch_date'),
    )
    
    def __repr__(self) -> str:
        return f"<IndexBasicInfo(index_code={self.index_code}, index_name={self.index_name})>"


class IndexDailyData(BaseFinancialModel, PartitionMixin):
    """
    指数日线数据模型
    存储指数的日线行情数据
    """
    __tablename__ = "index_daily_data"
    
    # 指数代码
    index_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="指数代码")
    
    # 交易日期
    trade_date: Mapped[date] = mapped_column(Date, nullable=False, comment="交易日期")
    
    # 开盘点位
    open_point: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 6), nullable=True, comment="开盘点位")
    
    # 最高点位
    high_point: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 6), nullable=True, comment="最高点位")
    
    # 最低点位
    low_point: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 6), nullable=True, comment="最低点位")
    
    # 收盘点位
    close_point: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 6), nullable=True, comment="收盘点位")
    
    # 前收盘点位
    pre_close_point: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 6), nullable=True, comment="前收盘点位")
    
    # 涨跌点数
    change_point: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 6), nullable=True, comment="涨跌点数")
    
    # 涨跌幅(%)
    change_pct: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="涨跌幅(%)")
    
    # 成交量（手）
    volume: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="成交量(手)")
    
    # 成交金额（万元）
    amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="成交金额(万元)")
    
    # 总市值（亿元）
    total_market_cap: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="总市值(亿元)")
    
    # 流通市值（亿元）
    float_market_cap: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="流通市值(亿元)")
    
    # 平均市盈率
    avg_pe: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="平均市盈率")
    
    # 平均市净率
    avg_pb: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="平均市净率")
    
    # 股息率(%)
    dividend_yield: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="股息率(%)")
    
    # 换手率(%)
    turnover_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="换手率(%)")
    
    # 上涨家数
    up_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="上涨家数")
    
    # 下跌家数
    down_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="下跌家数")
    
    # 平盘家数
    flat_count: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="平盘家数")
    
    __table_args__ = (
        UniqueConstraint('index_code', 'trade_date', name='uk_index_daily_code_date'),
        Index('idx_index_daily_code', 'index_code'),
        Index('idx_index_daily_date', 'trade_date'),
        Index('idx_index_daily_code_date', 'index_code', 'trade_date'),
        # 分区索引
        Index('idx_index_daily_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<IndexDailyData(index_code={self.index_code}, trade_date={self.trade_date}, close_point={self.close_point})>"


class IndexMinuteData(BaseFinancialModel, PartitionMixin):
    """
    指数分钟数据模型
    存储指数的分钟级行情数据
    """
    __tablename__ = "index_minute_data"
    
    # 指数代码
    index_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="指数代码")
    
    # 交易时间
    trade_time: Mapped[datetime] = mapped_column(DateTime, nullable=False, comment="交易时间")
    
    # 点位
    point: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 6), nullable=True, comment="点位")
    
    # 涨跌点数
    change_point: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 6), nullable=True, comment="涨跌点数")
    
    # 涨跌幅(%)
    change_pct: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="涨跌幅(%)")
    
    # 成交量（手）
    volume: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="成交量(手)")
    
    # 成交金额（万元）
    amount: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="成交金额(万元)")
    
    __table_args__ = (
        UniqueConstraint('index_code', 'trade_time', name='uk_index_minute_code_time'),
        Index('idx_index_minute_code', 'index_code'),
        Index('idx_index_minute_time', 'trade_time'),
        Index('idx_index_minute_code_time', 'index_code', 'trade_time'),
        # 分区索引
        Index('idx_index_minute_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<IndexMinuteData(index_code={self.index_code}, trade_time={self.trade_time}, point={self.point})>"


class IndexConstituent(BaseFinancialModel, PartitionMixin):
    """
    指数成分股模型
    存储指数成分股及权重信息
    """
    __tablename__ = "index_constituent"
    
    # 指数代码
    index_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="指数代码")
    
    # 成分股代码
    stock_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="成分股代码")
    
    # 生效日期
    effective_date: Mapped[date] = mapped_column(Date, nullable=False, comment="生效日期")
    
    # 权重(%)
    weight: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="权重(%)")
    
    # 纳入因子
    inclusion_factor: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 6), nullable=True, comment="纳入因子")
    
    # 自由流通股本（万股）
    free_float_shares: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="自由流通股本(万股)")
    
    # 调整股本（万股）
    adjusted_shares: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="调整股本(万股)")
    
    # 调整市值（万元）
    adjusted_market_cap: Mapped[Optional[Decimal]] = mapped_column(Numeric(20, 4), nullable=True, comment="调整市值(万元)")
    
    # 行业代码
    industry_code: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="行业代码")
    
    # 行业名称
    industry_name: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment="行业名称")
    
    # 是否有效
    is_active: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True, comment="是否有效")
    
    # 失效日期
    expiry_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True, comment="失效日期")
    
    __table_args__ = (
        UniqueConstraint('index_code', 'stock_code', 'effective_date', 
                        name='uk_index_constituent_code_stock_date'),
        Index('idx_index_constituent_index', 'index_code'),
        Index('idx_index_constituent_stock', 'stock_code'),
        Index('idx_index_constituent_date', 'effective_date'),
        Index('idx_index_constituent_industry', 'industry_code'),
        Index('idx_index_constituent_active', 'is_active'),
        # 分区索引
        Index('idx_index_constituent_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<IndexConstituent(index_code={self.index_code}, stock_code={self.stock_code}, weight={self.weight})>"


class IndexValuation(BaseFinancialModel, PartitionMixin):
    """
    指数估值数据模型
    存储指数的估值指标数据
    """
    __tablename__ = "index_valuation"
    
    # 指数代码
    index_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="指数代码")
    
    # 统计日期
    trade_date: Mapped[date] = mapped_column(Date, nullable=False, comment="统计日期")
    
    # 市盈率TTM
    pe_ttm: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="市盈率TTM")
    
    # 市盈率LYR
    pe_lyr: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="市盈率LYR")
    
    # 市净率
    pb: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="市净率")
    
    # 市销率TTM
    ps_ttm: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="市销率TTM")
    
    # 市现率TTM
    pcf_ttm: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="市现率TTM")
    
    # 股息率(%)
    dividend_yield: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="股息率(%)")
    
    # ROE(%)
    roe: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="ROE(%)")
    
    # ROA(%)
    roa: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="ROA(%)")
    
    # 净利润增长率(%)
    profit_growth: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="净利润增长率(%)")
    
    # 营收增长率(%)
    revenue_growth: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="营收增长率(%)")
    
    # PE分位数(%)
    pe_percentile: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2), nullable=True, comment="PE分位数(%)")
    
    # PB分位数(%)
    pb_percentile: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2), nullable=True, comment="PB分位数(%)")
    
    # 估值评级：低估, 合理, 高估
    valuation_rating: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, comment="估值评级")
    
    __table_args__ = (
        UniqueConstraint('index_code', 'trade_date', name='uk_index_valuation_code_date'),
        Index('idx_index_valuation_code', 'index_code'),
        Index('idx_index_valuation_date', 'trade_date'),
        Index('idx_index_valuation_pe_ttm', 'pe_ttm'),
        Index('idx_index_valuation_pb', 'pb'),
        Index('idx_index_valuation_rating', 'valuation_rating'),
        # 分区索引
        Index('idx_index_valuation_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<IndexValuation(index_code={self.index_code}, trade_date={self.trade_date}, pe_ttm={self.pe_ttm})>"


class IndexPerformance(BaseFinancialModel, PartitionMixin):
    """
    指数表现数据模型
    存储指数的历史表现和统计数据
    """
    __tablename__ = "index_performance"
    
    # 指数代码
    index_code: Mapped[str] = mapped_column(String(20), nullable=False, comment="指数代码")
    
    # 统计日期
    stat_date: Mapped[date] = mapped_column(Date, nullable=False, comment="统计日期")
    
    # 统计周期：1D, 1W, 1M, 3M, 6M, 1Y, 2Y, 3Y, 5Y, 10Y, YTD, ITD
    period: Mapped[str] = mapped_column(String(10), nullable=False, comment="统计周期")
    
    # 收益率(%)
    return_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="收益率(%)")
    
    # 年化收益率(%)
    annualized_return: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="年化收益率(%)")
    
    # 波动率(%)
    volatility: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="波动率(%)")
    
    # 夏普比率
    sharpe_ratio: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="夏普比率")
    
    # 最大回撤(%)
    max_drawdown: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="最大回撤(%)")
    
    # 卡玛比率
    calmar_ratio: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="卡玛比率")
    
    # 胜率(%)
    win_rate: Mapped[Optional[Decimal]] = mapped_column(Numeric(5, 2), nullable=True, comment="胜率(%)")
    
    # 盈亏比
    profit_loss_ratio: Mapped[Optional[Decimal]] = mapped_column(Numeric(10, 4), nullable=True, comment="盈亏比")
    
    # 上涨天数
    up_days: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="上涨天数")
    
    # 下跌天数
    down_days: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="下跌天数")
    
    # 平盘天数
    flat_days: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="平盘天数")
    
    # 总交易天数
    total_days: Mapped[Optional[Integer]] = mapped_column(Integer, nullable=True, comment="总交易天数")
    
    __table_args__ = (
        UniqueConstraint('index_code', 'stat_date', 'period', 
                        name='uk_index_performance_code_date_period'),
        Index('idx_index_performance_code', 'index_code'),
        Index('idx_index_performance_date', 'stat_date'),
        Index('idx_index_performance_period', 'period'),
        Index('idx_index_performance_return', 'return_rate'),
        Index('idx_index_performance_volatility', 'volatility'),
        # 分区索引
        Index('idx_index_performance_partition_date', 'partition_date'),
    )
    
    def __repr__(self) -> str:
        return f"<IndexPerformance(index_code={self.index_code}, period={self.period}, return_rate={self.return_rate})>"


# 导出所有指数相关模型
__all__ = [
    'IndexBasicInfo',
    'IndexDailyData',
    'IndexMinuteData',
    'IndexConstituent',
    'IndexValuation',
    'IndexPerformance',
]